<template>
	<view ref="node" name="LyTreeNode" v-show="node?.visible" class="ly-tree-node" :class="{
		'is-expanded': expanded,
		'is-hidden': !node?.visible,
		'is-checked': !node?.disabled && node?.checked
	}" role="treeitem" @tap.stop="handleClick">
		<view class="ly-tree-node__content" :class="{
		'is-current': node?.isCurrent && highlightCurrent
	}" :style="{
		'padding-left': (node?.level - 1) * Number(indent) + 'rpx'
	}">
			<image v-if="node?.isLeaf" :src="otherClass" mode="widthFix" class="ly-tree-node__icon"></image>
			<image v-if="node?.expanded && !node.isLeaf" :src="iconClass" mode="widthFix" class="ly-tree-node__icon"
				@tap.stop="handleExpandIconClick"></image>
			<image v-if="!node?.expanded && !node.isLeaf" :src="openClass" mode="widthFix" class="ly-tree-node__icon"
				@tap.stop="handleExpandIconClick"></image>

			<ly-checkbox v-if="(checkboxVisible || radioVisible) && Number(node.data.id) > 0"
				:type="checkboxVisible ? 'checkbox' : 'radio'" :checked="node?.checked"
				:indeterminate="node?.indeterminate" :disabled="!!node?.disabled"
				@check="handleCheckChange(!node?.checked)" />
			<text v-if="node?.loading" class="ly-tree-node__loading-icon ly-iconfont ly-icon-loading">
			</text>

			<template v-if="node?.icon && node?.icon.length > 0">
				<image v-if="node?.icon.indexOf('/') !== -1" class="ly-tree-node__icon" mode="widthFix"
					:src="node?.icon" @error="handleImageError">
				</image>
				<text v-else class="ly-tree-node__icon" :class="node?.icon">
				</text>
			</template>
			<text class="ly-tree-node__label"
				@click="(checkboxVisible || radioVisible) && Number(node.data.id) > 0 ? handleCheckChange(!node?.checked) : ''">{{
		node?.label }}</text>
		</view>

		<view v-if="!renderAfterExpand || childNodeRendered" v-show="expanded" class="ly-tree-node__children"
			role="group">
			<lyNode v-for="cNodeId in node?.childNodesId" :nodeId="cNodeId" :render-after-expand="renderAfterExpand"
				:show-checkbox="showCheckbox" :show-radio="showRadio" :check-only-leaf="checkOnlyLeaf"
				:key="getNodeKey(cNodeId)" :indent="indent" :open-class="openClass" :icon-class="iconClass"
				:otherClass="otherClass">
			</lyNode>
		</view>
	</view>
</template>

<script lang="ts" setup name="ly-tree-node">
import { reactive, ref, inject, watch, onMounted, computed, nextTick, onDeactivated } from "vue";
import { getNodeKey as _getNodeKey } from './tool/util';
import type TreeStore from './model/tree-store';
import lyCheckbox from './components/ly-checkbox.vue';
import lyNode from './node.vue'
interface Ip {
	nodeId: string | number
	renderAfterExpand?: boolean
	checkOnlyLeaf?: boolean
	showCheckbox?: boolean
	showRadio?: boolean
	indent?: number
	iconClass?: string
	openClass?: string
	otherClass?: string

}

const p = withDefaults(defineProps<Ip>(), {
	renderAfterExpand: true,
	checkOnlyLeaf: false,
	showCheckbox: false,
	showRadio: false
})



const tree = inject<{ store: TreeStore, nodeKey: string, expandOnCheckNode: boolean, checkStrictly: boolean, elId: string, accordion: boolean, defaultNodeIcon: string, $emit: any, highlightCurrent: any, props: any, checkOnClickNode: any, currentNode: any, expandOnClickNode: any }>('tree', {})

const node = ref(tree.store.nodesMap[p.nodeId])

const expanded = ref(false)
const childNodeRendered = ref(false)
const highlightCurrent = ref(false)
const oldChecked = ref(false)
const oldIndeterminate = ref(false)

const checkboxVisible = computed(() => {
	return p.checkOnlyLeaf ? p.showCheckbox && node.value?.isLeaf : p.showCheckbox
})

const radioVisible = computed(() => {
	return p.checkOnlyLeaf ? p.showRadio && node.value?.isLeaf : p.showRadio
})



function getNodeKey(nodeId: string) {
	let node = tree?.store.root.getChildNodes([nodeId])[0];
	return _getNodeKey(tree?.nodeKey, node.value?.data);
}

const indeterminate = ref()
function handleSelectChange(checked: boolean, _indeterminate: boolean) {

	if (oldChecked.value !== checked && oldIndeterminate.value !== _indeterminate) {

		if (p.checkOnlyLeaf && !node.value?.isLeaf) return;

		if (checkboxVisible.value) {
			const allNodes = tree?.store._getAllNodes();
			tree?.$emit('check-change', {
				checked,
				indeterminate: _indeterminate,
				node: node.value,
				data: node.value?.data,
				checkedall: allNodes?.every(item => item.checked)
			});
		} else {
			tree?.$emit('radio-change', {
				checked,
				node: node.value,
				data: node.value?.data,
				checkedall: false
			});
		}
	}

	if (!expanded.value && tree?.expandOnCheckNode && checked) {
		handleExpandIconClick();
	}

	oldChecked.value = checked;
	indeterminate.value = _indeterminate;
}

function handleExpandIconClick() {
	if (node.value?.isLeaf) return;

	if (expanded.value) {
		tree?.$emit('node-collapse', node.value);
		node.value?.collapse();
	} else {
		node.value?.expand();
		tree?.$emit('node-expand', node.value);

		if (tree?.accordion) {
			uni.$emit(`${tree?.elId}-tree-node-expand`, node.value);
		}
	}
}


function handleCheckChange(checked: boolean) {
	if (node.value?.disabled) return;

	if (checkboxVisible) {
		node.value.setChecked(checked, !(tree?.checkStrictly || p.checkOnlyLeaf));
	} else {
		node.value?.setRadioChecked(checked);
	}

	nextTick(() => {
		tree?.$emit('check', {
			node: node.value,
			data: node.value?.data,
			checkedNodes: tree?.store.getCheckedNodes(),
			checkedKeys: tree?.store.getCheckedKeys(),
			halfCheckedNodes: tree?.store.getHalfCheckedNodes(),
			halfCheckedKeys: tree?.store.getHalfCheckedKeys(),
			checked
		});
	});
}

function handleImageError() {
	if (node.value) {
		node.value.icon = tree?.defaultNodeIcon;
	}
}

function handleClick() {
	if (tree) {
		tree?.store.setCurrentNode(node.value);
		tree?.$emit('current-change', {
			node: node.value,
			data: tree?.store.currentNode ? tree?.store.currentNode.data : null,
			currentNode: tree?.store.currentNode
		});
		tree.currentNode = node.value;

		if (tree?.expandOnClickNode) {
			handleExpandIconClick();
		}

		if (tree?.checkOnClickNode && !node.value?.disabled) {
			(checkboxVisible || radioVisible.value) && handleCheckChange(!node.value?.checked);
		}

		tree?.$emit('node-click', node.value);
	}

}

onMounted(() => {
	if (!tree) {
		throw new Error('Can not find node\'s tree?.');
	}

	node.value = tree?.store.nodesMap[p.nodeId];

	highlightCurrent.value = tree?.highlightCurrent;

	if (node.value?.expanded) {
		expanded.value = true;
		childNodeRendered.value = true;
	}

	const props = tree?.props || {};
	// const childrenKey = props['children'] || 'children';
	watch(() => node.value?.data?.children, () => {
		node.value?.updateChildren();
	});

	if (tree?.accordion) {
		uni.$on(`${tree?.elId}-tree-node-expand`, n => {
			if (node.value?.id !== node.value?.id && node.value?.level === n.level) {
				node.value?.collapse();
			}
		});
	}
})



onDeactivated(() => {

})

watch(() => node.value?.indeterminate, val => {
	handleSelectChange(!!node.value?.checked, !!val)
})

watch(() => node.value?.checked, val => {
	handleSelectChange(!!val, !!node.value?.indeterminate)
})


watch(() => node.value?.expanded, val => {
	nextTick(() => expanded.value = !!val)
	if (val) {
		childNodeRendered.value = true;
	}
})





</script>

<style>
.ly-tree-node {
	white-space: nowrap;
	outline: 0
}

.ly-tree-node__content {
	display: flex;
	align-items: center;
	height: 70rpx;
}

.ly-tree-node__content.is-current {
	background-color: #F5F7FA;
}

.ly-tree-node__content>.ly-tree-node__expand-icon {
	padding: 12rpx;
}

.ly-tree-node__checkbox {
	display: flex;
	margin-right: 16rpx;
	width: 40rpx;
	height: 40rpx;
}

.ly-tree-node__checkbox>image {
	width: 40rpx;
	height: 40rpx;
}

.ly-tree-node__expand-icon {
	color: #C0C4CC;
	font-size: 28rpx;
	-webkit-transform: rotate(0);
	transform: rotate(0);
	-webkit-transition: -webkit-transform .3s ease-in-out;
	transition: -webkit-transform .3s ease-in-out;
	transition: transform .3s ease-in-out;
	transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out
}

.ly-tree-node__expand-icon.expanded {
	-webkit-transform: rotate(90deg);
	transform: rotate(90deg)
}

.ly-tree-node__expand-icon.is-leaf {
	color: transparent;
}

.ly-tree-node__icon {
	width: 34rpx;
	height: 34rpx;
	overflow: hidden;
	margin-right: 16rpx;
}

.ly-tree-node__label {
	font-size: 28rpx;
	color: #333333;
	flex: 1;
	display: flex;
	height: 70rpx;
	align-items: center;
}

.ly-tree-node__loading-icon {
	margin-right: 16rpx;
	font-size: 28rpx;
	color: #C0C4CC;
	-webkit-animation: rotating 2s linear infinite;
	animation: rotating 2s linear infinite
}

.ly-tree-node>.ly-tree-node__children {
	overflow: hidden;
	background-color: transparent
}

.ly-tree-node>.ly-tree-node__children.collapse-transition {
	transition: height .3s ease-in-out;
}

.ly-tree-node.is-expanded>.ly-tree-node__children {
	display: block
}

.ly-tree-node_collapse {
	overflow: hidden;
	padding-top: 0;
	padding-bottom: 0;
}

/* lyTree-end */

/* iconfont-start */
@font-face {
	font-family: "ly-iconfont";
	src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAPsAAsAAAAACKwAAAOeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqFDIQPATYCJAMMCwgABCAFhG0HQBtfB8gekiSCdAwUAKgCFMA5Hj7H0PeTlABUr57PVyGqugqzSWJnNwWoWJjx/9rUr4TPL1ZSQpU2mycqwoRwIN3p+MkqMqyEW+OtMBLPSUBb8v//XtWMKTavxYIUsT/Wy1qbQzkBDOYEKGB7dVpPyVqgCnJNwvMvhZl10nMCtQbFoPVhY8ZDncJfF4grbqpQ13AqE52hWqgcOFrEQ6hWnW5VfMCD7Pfjn4WoI6nI/K0bl0MNGPBz0qcflVqYnvCA4vNDPUXGPFCIw8HgtsqiOK9SrW2smm6sVITElWlpISMdVBn8wyMJopLfXg+myZ48KCrSkvj9g37U1ItbXYke4APwXxK3N4TuehyBfmM0I3zbNdt7uk3VnjPtzX0rnIl7z7bZvb/thHohsu9QuykKo+Cws4nL7LsPmI3n2qN9B9upZEIKd4hu0NCKi0rt7fNtdl+I1N25hOJMDQK6odS123tROR7Pg8toEhDaF+kR0TYjxW6M58F5+ZNQOxmZHtE2g+IYjxjlNy/yIRQpCmrgq5R4/3jx8PvT8Ha8d3/xiLnt4EGyaDnznzRv8vpyZ+9TFHf/ntX9e59A+b6+fPHd5+dy0wYHVvHOroWbnWe879O9DnL53bN/gUHuwm28b/n8i/V3ry4E3IoXNqS6Rvs0LhJxeNVjoUkM3LKosU+0a6rh45FVvLt+2oz7Zd53b4QOy7/9snDXHbqVu+A+f8r7PnM2H8kXrWm5c8/vLu7LqRee7HW637mz3kHc5U/RCXf25d7G8tkdgEfwIpzpkknGpaMw3ww55q9Mn9OQNyua/wB/49OOWydn4eL/6roCfjx6FMmcxfJStYRKfd3UwoHiML4rF4uMSK+SvYTuNxMHrpl8yd3Q6v32cAeo/KFaowBJlQHIqo3zi3geKtRZhErVlqDWnOGn67QRKkWpwaw1AkKza5A0egFZszf8In4HFTp9h0rNUQm1NqP1lXUmgyuDBVUlNYi2gHA98FnokUreOZaac1xV1JlMMZGKEs+QdCLVrgynPhUcO0pzzYyUjDAReGSYeBl13YCEIrCpLhOWlGE+mWRD35TQAw8UawRKJVEGQrMAwekCPpaMlpTOz49FmeZwqcREX1t3Ikoo4dMTaQmpBfzhRn9R30uZXTKXKUOSmLSKEQIeYhjqKZcrcIzhMLLRrJMSrA35UF4yGMaWGhPHm733dwJq+Z/NkSJHUXemCirjgpuWrHMD1eC+mQUAAAA=') format('woff2');
}

.ly-iconfont {
	font-family: "ly-iconfont" !important;
	font-size: 30rpx;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.ly-icon-caret-right:before {
	content: "\e8ee";
}

.ly-icon-loading:before {
	content: "\e657";
}

/* iconfont-end */

/* animate-start */
@keyframes rotating {
	0% {
		-webkit-transform: rotateZ(0);
		transform: rotateZ(0)
	}

	100% {
		-webkit-transform: rotateZ(360deg);
		transform: rotateZ(360deg)
	}
}

/* animate-end */
</style>